<?php
class Cache {	         
    protected $cacheMap = array(
        'VideoInfo' =>  array('ver'=>'2', 'expire'=>600, 'type'=>'memcache'),
        'UserInfo'  =>  array('ver'=>'1', 'expire'=>900,  'type'=>'memcache'),
        'GameInfo'  =>  array('ver'=>'1', 'expire'=>3600,  'type'=>'memcache'),
        'PageCache'  =>  array('ver'=>'16', 'expire'=>600,  'type'=>'memcache'), //静态页面缓存
        'VideoListByTag'  =>  array('ver'=>'1', 'expire'=>1800,  'type'=>'memcache'), //通过标签获取视频
        'VideoListByRelate'  =>  array('ver'=>'1', 'expire'=>86400,  'type'=>'memcache'), //相关视频
        'videolistBystatus' => array('ver'=>'2', 'expire'=>7200,  'type'=>'memcache'), //按视频发布状态获取列表
        'DWMRank'  =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //日周月排行榜
        'HuyaLive' =>  array('ver'=>'5', 'expire'=>600,  'type'=>'redis'),
        'MirrorContent' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //发布器镜像
        'TplContent' =>  array('ver'=>'1', 'expire'=>1800,  'type'=>'memcache'), //发布器模板内容
        'WapVideoSrc' =>  array('ver'=>'1', 'expire'=>600,  'type'=>'memcache'), //移动端视频源地址(m.v.huya.com独有)
        'VideoSrc' =>  array('ver'=>'1', 'expire'=>600,  'type'=>'memcache'), //PC端视频源地址
        'Anime' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫基础信息
        'AnimeByTag' =>  array('ver'=>'3', 'expire'=>600,  'type'=>'memcache'), //获取动漫标签相关剧集
        'AnimePage' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫分页
        'AnimeVideo' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫视频
        'AnimeList' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫剧集列表视频
        'AnimeSort' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫剧集排序
        'AnimeArticleInfo' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //动漫剧集所有文章信息
        'ZhiboApi' =>  array('ver'=>'1', 'expire'=>300,  'type'=>'memcache'),   
        'VidsByCmsTag' =>  array('ver'=>'1', 'expire'=>7200,  'type'=>'memcache'),     
        'ProfitPlaySum' => array('ver' => '2', 'expire' => 86400, 'type' => 'memcache'),//旧播客分成播放量包装数据，缓存一天（可能将废弃）
        'ProfitDateSum' => array('ver' => '2', 'expire' => 86400, 'type' => 'memcache'),//旧播客分成播放量本地库数据(date索引)，缓存一天（可能将废弃）
        'ProfitVidSum' => array('ver' => '2', 'expire' => 86400, 'type' => 'memcache'),//旧播客分成播放量本地库数据(vid索引)，缓存一天（可能将废弃）
        'RevenuePlaySum' => array('ver' => '5', 'expire' => 86400, 'type' => 'memcache'),//新播客分成播放量包装数据，缓存一天
        'RevenueDetailsByYyuid' => array('ver' => '5', 'expire' => 86400, 'type' => 'memcache'),//新播客分成播放量本地库数据(按YYUID查找)，缓存一天
        'RevenueDetailsByVids' => array('ver' => '5', 'expire' => 86400, 'type' => 'memcache'),//新播客分成播放量本地库数据(按VIDS查找)，缓存一天
        'SearchData' =>  array('ver'=>'1', 'expire'=>3600,  'type'=>'memcache'), //海度搜索
        'LolVideosByFilterId' =>  array('ver'=>'1', 'expire'=>600,  'type'=>'memcache'), //lol专区列表缓存
        'BbsVideoHot' =>  array('ver'=>'1', 'expire'=>600,  'type'=>'memcache'), //论坛热门视频接口缓存
        'UsersByFilterName' =>  array('ver'=>'2', 'expire'=>600,  'type'=>'memcache'), //过滤器名称获取推荐用户信息缓存
        'RecommendUser' =>  array('ver'=>'3', 'expire'=>600,  'type'=>'memcache'), //推荐用户信息缓存
        'PcgVideo' => array('ver'=>'3', 'expire'=>600,  'type'=>'memcache'), //太平洋网视频
        'Other' =>  array('ver'=>'12', 'expire'=>600,  'type'=>'memcache'), //未归类的缓存        
    );
    
    public function __construct(){
        //统一转成小写处理
        foreach($this->cacheMap as $k=>$v){
            $k = strtolower($k);
            $this->cacheMap[$k] = $v; 
        }           
    }
    
    public function getMemCache(){
        static $cacheObj;
        if( !$cacheObj ){ //单例
            $cacheObj = obj('dwCache', array($GLOBALS['app_id']), '', true);
        }
        return $cacheObj;
    }
    
    public function getRedis(){
        static $cacheObj;
        if( !$cacheObj ){  //单例
            $cacheObj= obj('dwRedis');
        }
        return $cacheObj;
    }

    public function call($callMethod, $params, $cacheMethod = 'other'){
       list($class, $method) = explode('::', $callMethod);
       $cacheParams = $params;
       if( 'other'==$cacheMethod ){
           $key = strtolower($class.'_'.$method);
           array_unshift($cacheParams, $key);
       }
       
       //获取缓存
       $cacheGetMethod = 'get'.$cacheMethod;
       $cache = call_user_func_array(array($this, $cacheGetMethod), $cacheParams);
       if( $cache ) return $cache;
       
       //获取数据
       $result = call_user_func_array(array(obj($class), $method), $params);
       if( false=== $result ) return $result;
       
       //写入缓存
       array_push($cacheParams, $result);
       $cacheSetMethod = 'set'.$cacheMethod;
       call_user_func_array(array($this, $cacheSetMethod), $cacheParams);
       
       return $result;
    }
    
    public function __call($method, $params){
        $method = strtolower($method);
        $op = substr($method, 0, 3);
        $methodName = substr($method, 3);
        
        if( !in_array($op, array('get', 'set', 'del', 'exp')) ){
            throw new Exception("'{$method}' method must begin with 'get', 'set', 'del','exp'");
        }     
        if( !isset($this->cacheMap[$methodName]) ){
            throw new Exception("'{$method}' method does not exist");
        }
                
        if( 'set'==$op ) $data = array_pop($params);
        if( 0==count($params) ){
            throw new Exception("cache params error");
        }
        
        foreach ($params as $k => $v) {
            if (is_numeric($v)) $params[$k] = strval($v);//数字参数最终处理为字符串
        }
            
        $hashKey = $this->cacheMap[$methodName]['ver'].'_'.md5(json_encode($params));      
        $cacheType = $this->cacheMap[$methodName]['type'];
        
        if( 'get'==$op && CACHE_GET_ABLE){
            if( !empty($this->cacheMap[$methodName]['expire_special']) ){
                $expire = $this->cacheMap[$methodName]['expire_special'];
                $this->cacheMap[$methodName]['expire_special'] = 0;
               
            }else{
                $expire = $this->cacheMap[$methodName]['expire'] - mt_rand(0, 10);
            }
        
            return $this->_get($cacheType, $methodName, $hashKey, $expire);   
        }else if( 'set'==$op && CACHE_SET_ABLE ){
            return $this->_set($cacheType, $methodName, $hashKey, $data);   
        }else if( 'del'==$op ){
            return $this->_del($cacheType, $methodName, $hashKey);
        }else if( 'exp'==$op ){
            return $this->cacheMap[$methodName]['expire_special'] = intval($params[0]);
        }else{
            return NULL;
        }
    }

    protected function _get($cacheType, $methodName, $hashKey, $expire){
        if( 'redis'==$cacheType ){
            $value = $this->getRedis()->hGet($methodName, $hashKey);
            $value = @json_decode($value, true);
        }else{
            $value = $this->getMemCache()->get($methodName.'_'.$hashKey);
        }
        
        if( !empty($value['data']) && ($value['time']+$expire)>time() ){
            return $value['data'];
        }
        return NULL;
    }

    protected function _set($cacheType, $methodName, $hashKey, $data){
        $value = array('data'=>$data, 'time'=>time());
        if( 'redis'==$cacheType ){
            $value = json_encode( $value );
            return $this->getRedis()->hSet($methodName, $hashKey, $value);
        }else{
            return $this->getMemCache()->set($methodName.'_'.$hashKey, $value, 86400); 
        }
    }   

    protected function _del($cacheType, $methodName, $hashKey){
        if( 'redis'==$cacheType ){
            return $this->getRedis()->hDel($methodName, $hashKey);
        }else{
            return $this->getMemCache()->delete($methodName.'_'.$hashKey);
        }
    }
}